import constants as con
import pygame
import pymunk as pm
import pymunk._chipmunk as cp
from pymunk import Vec2d
import mainmenu

import pygame.color as colors

import xzplatform
import xzbrick
import xzcoin
import xzplayer
import xzfamily
import xzgoal
import postgame
import gamebg

class Game(object):
    def __init__(self):

        pygame.init()
        pygame.mixer.init()
        pygame.display.set_caption(con.window_caption)

        try:
            # try to load our cool bitmap font first
            self.font = pygame.font.Font('data/PressStart2P.ttf',16)
        except:
            self.font = pygame.font.Font(None,16)

        self.music = pygame.mixer.music.load('data/Death-n-Taxes.wav')

        self.bpmadjusting = 0
        self.bpm = 60
        self.beat = 1000
        self.thump = 0
        self.maxfamily = 5
        self.pattern = [ 'b','c','b','c' ]

        self.screensize = self.screenw,self.screenh = con.window_size
        
        self.scoreboard_height = 60
        self.scoreboard = pygame.Rect(0,0,con.window_size[0],self.scoreboard_height)

        self.mode = pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.HWSURFACE

        if pygame.display.mode_ok(self.screensize,self.mode):
            self.screen = pygame.display.set_mode(self.screensize,pygame.FULLSCREEN | pygame.DOUBLEBUF | pygame.HWSURFACE)
        else:
            self.screen = pygame.display.set_mode(self.screensize)

        pygame.mixer.init()

        self.clickrange = int(con.window_size[0] * 0.046875)

        pm.init_pymunk()
        self.space = pm.Space()
        self.space.gravity = (0.0, -100.0)
        self.space.resize_static_hash()
        self.space.resize_active_hash()

        self.sprites = pygame.sprite.LayeredUpdates()
        self.bg = gamebg.BG(self)

        self.state = 'Menu'
        self.exit = False
        self.gameTime = 0
        self.mainmenu = mainmenu.Menu(self)

        self.player = xzplayer.Player(self)
        self.platform = xzplatform.Platform(self)
        self.instructions = None

        self.mom = xzfamily.Family('Mom',0,self)
        self.son = xzfamily.Family('Son',1,self)
        self.daughter = xzfamily.Family('Daughter',-1,self)
        self.baby = xzfamily.Family('Baby',2,self)
        self.cat = xzfamily.Family('Cat',-2,self)
        #self.dog = xzfamily.Family('Dog',3,self)
        
        self.reset()

    def reset(self):

        self.timer = 300
        #self.timer = 15

        self.income = 0
        self.score = 0
        self.pouch = 0
        self.taxes = 0
        self.failure = 0
        self.drops = 0

        self.fps = 0

        self.drawqueue = []
        self.bricklist = []
        self.coinlist = []
        self.goals = []

        self.alive = self.maxfamily
        #self.alive = 0

    def scanForNeed(self,need):
        spree = 0
        ret = 0

        if self.mom.need == need:
            ret = self.mom.happy()
            spree += 1
            if ret:
                print "mom cured!!"
                self.goals.append( xzgoal.Goal( self, ret, 4))
        if self.son.need == need:
            ret = self.son.happy()
            spree += 1
            if ret:
                print "son cured!!"
                self.goals.append( xzgoal.Goal( self, ret, 4))
        if self.daughter.need == need:
            ret = self.daughter.happy()
            spree += 1
            if ret:
                print "daughter cured!!"
                self.goals.append( xzgoal.Goal( self, ret, 4))
        if self.baby.need == need:
            ret = self.baby.happy()
            spree += 1
            if ret:
                print "baby cured!!"
                self.goals.append( xzgoal.Goal( self, ret, 4))
        if self.cat.need == need:
            ret = self.cat.happy()
            spree += 1
            if ret:
                print "cat cured!!"
                self.goals.append( xzgoal.Goal( self, ret, 4))

        self.income += 200 * spree
        if spree > 1:
            self.goals.append( xzgoal.Goal( self, "%dx COMBO!!" % (spree), 4))
        elif spree == 1:
            self.goals.append( xzgoal.Goal( self, "NEED SATISFIED!!", 4))

    def update(self):
        self.sprites.update()

        if self.timer <= 0:
            for brick in self.bricklist[:]:
                brick.purge()
            for coin in self.coinlist[:]:
                coin.purge()

            print "YOU'RE WINNER"
            pygame.mixer.music.stop()
            self.postgame = postgame.Postgame(self,'win')
            self.state = 'Fadeout'
            self.message = self.font.render("YOU'RE WINNER!", True, (255,0,0))
            self.val = 200
        elif self.alive > 0:
            for brick in self.bricklist[:]:
                body = brick.body

                if body.position.y < 0:
                    print "deleting brick"
                    brick.purge()
                    self.drops +=1

            for coin in self.coinlist[:]:
                body = coin.body

                if body.position.y < 0:
                    print "deleting coin"
                    coin.purge()
                    self.taxes += 100

        else:
             for brick in self.bricklist[:]:
                 brick.purge()
             for coin in self.coinlist[:]:
                 coin.purge()

             print "GAME OVER, MAN"
             pygame.mixer.music.stop()
             self.postgame = postgame.Postgame(self,'lose')
             self.state = 'Fadeout'
             self.message = self.font.render("GAME OVER", True, (255,0,0))
             self.val = 200

    def newBrick(self):
        buf = xzbrick.Brick(self)
        self.bricklist.append(buf)

    def newCoin(self):
        self.income += 100
        buf = xzcoin.Coin(self)
        self.coinlist.append(buf)

    def redraw(self):

        self.screen.fill(con.bgcolor)

        if self.state == 'Menu':
            self.mainmenu.redraw()
        elif self.state == 'Play':
            self.sprites.draw(self.screen)
            self.drawScoreboard()
            #self.player.pymunkDraw(self.screen)
            #self.platform.pymunkDraw(self.screen)
            #for brick in self.bricks:
            #    brick.pymunkDraw(self.screen)
            #for coin in self.coins:
            #    coin.pymunkDraw(self.screen)

            for  goal in self.goals:
                goal.redraw()
        elif self.state == 'Fadeout':
            self.sprites.draw(self.screen)
            self.drawScoreboard()
            for goal in self.goals:
                goal.purge()

            self.screen.fill( (self.val,self.val,self.val,self.val), (0,0,con.window_size[0],con.window_size[1]), special_flags=pygame.BLEND_RGB_MULT)
            self.screen.blit(self.message, (int( (con.window_size[0] / 2) - (self.message.get_width() / 2)),int(con.window_size[1] / 2)))
            self.val -= 2

            if self.val <= 0:
                self.state = 'Postgame'

        elif self.state == 'Scores':
            self.topscores.redraw()
        elif self.state == 'Instructions':
            self.instructions.redraw()
        elif self.state == 'Postgame':
            self.postgame.redraw()
        else:
            print "programmer did something stupid: ", self.state

        for pos in self.drawqueue:
            pygame.draw.circle(self.screen, colors.THECOLORS["red"], pos, int(con.window_size[0] * 0.05), 2)
            #pygame.draw.rect(self.screen, colors.THECOLORS["cyan"], pos, 1)
            self.drawqueue = []

        #fps = "fps: %d" % (self.fps)
        #str = self.font.render(fps, True, con.fgcolor)
        #self.screen.blit(str,(con.window_size[0] - str.get_width(),con.window_size[1] - str.get_height()))

        pygame.display.flip()

    def drawScoreboard(self):

        self.screen.fill(con.menubg, self.scoreboard)
        #pygame.draw.line(self.screen, colors.THECOLORS["white"], (0,self.scoreboard_height), (con.window_size[0],self.scoreboard_height), 3)

        scorestr = " Spent: %010d  Time: %03d" % (self.score, self.timer)
        score = self.font.render(scorestr, True, con.fgcolor)
        self.screen.blit(score,(0,10))

        taxstr = " Taxes: %010d  Fails: %d" % (self.taxes,self.failure)
        taxes = self.font.render(taxstr, True, con.fgcolor)
        self.screen.blit(taxes,(0,33))

        ball_size = 15
        x = con.window_size[0] - (ball_size * 5 * 2)
        y = ball_size + 5
        for i in range(5):
            if i < self.pouch:
                pygame.draw.circle(self.screen, colors.THECOLORS["yellow"], (x,y), ball_size)
            else:
                pygame.draw.circle(self.screen, con.fgcolor, (x,y), ball_size, 2)
            x += ball_size * 2

    def mouseDown(self):

        self.drawqueue = []

        p = pygame.mouse.get_pos()

        if Vec2d.get_distance(self.player.body.position, (p[0],con.flipy(p[1]))) < (self.clickrange * 2):

            # first check if we have a brick under the click
            ps = pm.Vec2d(p[0], con.flipy(p[1]))
            shape = self.space.point_query_first(ps,4)
            if shape is not None:
                #print "found brick"
                loc = con.to_pygame(shape.body.position)
                if shape.type == 'brick':
                    if self.pouch:
                        if shape.parent.coins < 2:
                            shape.parent.coins += 1
                            self.pouch -= 1
                        elif shape.parent.coins == 2:
                            self.pouch -= 1
                            shape.parent.play()
                            shape.parent.purge()
                            self.score += 100
                            self.scanForNeed(shape.parent.need)
                    return

            # gather all coins near the mouse click
            (box,rect) = self.bb(pygame.mouse.get_pos())
            self.drawqueue.append(rect.center)

            hits = self.bbq(box,4)

            play = 0
            if hits is not None:
                for shape in hits:
                    if shape.type == 'coin':
                        #print "found coin"
                        if self.pouch <= 4:
                            if not play:
                                shape.parent.play()
                                play = 1
                            self.pouch += 1
                            shape.parent.purge()

    def bbq(self, bb, layers = -1, groups = 0):
        self.__query_hits = []

        def cf(_shape, data):
            shape = self.space._shapes[_shape.contents.hashid]
            self.__query_hits.append(shape)

        f = cp.cpSpaceBBQueryFunc(cf)
        cp.cpSpaceBBQuery(self.space._space, bb._bb, layers, groups, f, None)

        return self.__query_hits

    def bb(self,pos):
        size = self.clickrange
        left = pos[0] - size
        top = pos[1] - size
        bottom = pos[1] + size
        right = pos[0] + size
        return (pm.BB(left,con.flipy(bottom),right,con.flipy(top)), pygame.Rect(left,top,right - left,bottom - top))
